查看原文
其他

通过ObRegisterCallbacks学习对象监控与反对象监控

1900 看雪学苑 2022-07-01


本文为看雪论坛优秀文章
看雪论坛作者ID:1900



1


简介


实现环境:WIN7 X86。

要实现的目标:对进程对象和线程对象实现监控来保护目标进程不被任务管理器关掉。


2


对象监控


在Windows中可以通过ObRegisterCallbacks来设置对象监控,该函数的定义如下:
NTSTATUS ObRegisterCallbacks( IN POB_CALLBACK_REGISTRATION CallBackRegistration, OUT PVOID *RegistrationHandle);



OB_CALLBACK_REGISTRATION结构体的定义如下:
typedef struct _OB_CALLBACK_REGISTRATION { __in USHORT Version; __in USHORT OperationRegistrationCount; __in UNICODE_STRING Altitude; __in PVOID RegistrationContext; __in OB_OPERATION_REGISTRATION *OperationRegistration;} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;



OB_OPERATION_REGISTRATION结构体定义如下:
typedef struct _OB_OPERATION_REGISTRATION { __in POBJECT_TYPE *ObjectType; __in OB_OPERATION Operations; __in POB_PRE_OPERATION_CALLBACK PreOperation; __in POB_POST_OPERATION_CALLBACK PostOperation;} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;



ObjectPreCallback和ObjectPostCallback的定义如下,它们的参数是一样的,只是返回值不同。
OB_PREOP_CALLBACK_STATUS ObjectPreCallback( __in PVOID RegistrationContext, __in POB_PRE_OPERATION_INFORMATION OperationInformation);
VOID ObjectPostCallback( __in PVOID RegistrationContext, __in POB_POST_OPERATION_INFORMATION OperationInformation );



最后在介绍一个函数,它可以根据线程对象获得进程对象。该函数的定义如下:
PEPROCESS IoThreadToProcess( IN PETHREAD Thread);

根据以上内容就可以实现对进程的保护,具体代码如下:
#include <ntifs.h>
#define PROCESS_NAME "demo.exe" // 要保护的进程名#define PROCESS_TERMINATE 0x0001
typedef struct _KLDR_DATA_TABLE_ENTRY{ LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID DllBase; PVOID EntryPoint; UINT32 SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; UINT32 Flags; USHORT LoadCount; USHORT TlsIndex; LIST_ENTRY HashLinks; PVOID SectionPointer; UINT32 CheckSum; UINT32 TimeDateStamp; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
// 未导出函数声明PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);VOID DriverUnload(IN PDRIVER_OBJECT driverObject);BOOLEAN IsProtectProcess(PEPROCESS pEProcess); // 判断是否是要保护的进程NTSTATUS SetProcessCallback(); // 设置进程回调函数NTSTATUS SetThreadCallback(); // 设置线程回调函数OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo); // 进程回调函数OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo); // 线程回调函数
// 进程回调对象句柄HANDLE g_obProcessHandle;// 线程回调对象句柄HANDLE g_obThreadHandle;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){ NTSTATUS status = STATUS_SUCCESS; PKLDR_DATA_TABLE_ENTRY pLdrData = NULL;
DbgPrint("驱动加载完成\r\n"); pLdrData = (PKLDR_DATA_TABLE_ENTRY)driverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20;
if (NT_SUCCESS(SetProcessCallback())) { DbgPrint("进程回调函数设置完成\r\n"); }
if (NT_SUCCESS(SetThreadCallback())) { DbgPrint("线程回调函数设置完成\r\n"); }exit: driverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS;}
NTSTATUS SetProcessCallback(){ NTSTATUS status = STATUS_SUCCESS; OB_CALLBACK_REGISTRATION obCallbackReg = { 0 }; OB_OPERATION_REGISTRATION obOperationReg = { 0 };
RtlZeroMemory(&obCallbackReg, sizeof(obCallbackReg)); RtlZeroMemory(&obOperationReg, sizeof(obOperationReg));
//设置OB_OPERATION_REGISTRATION obOperationReg.ObjectType = PsProcessType; obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ProcessPreCall);
//设置OB_CALLBACK_REGISTRATION obCallbackReg.Version = ObGetFilterVersion(); obCallbackReg.OperationRegistrationCount = 1; obCallbackReg.RegistrationContext = NULL; RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900"); obCallbackReg.OperationRegistration = &obOperationReg;
status = ObRegisterCallbacks(&obCallbackReg, &g_obProcessHandle); if (!NT_SUCCESS(status)) { DbgPrint("ObRegisterCallbacks Error 0x%X\r\n", status); }
return status;}
OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){ PEPROCESS pEProcess = NULL;
// 判断对象类型 if (*PsProcessType != pObPreOperationInfo->ObjectType) { goto exit; }
// 获取进程结构体对象 pEProcess = (PEPROCESS)pObPreOperationInfo->Object; if (IsProtectProcess(pEProcess)) // 是否是要保护的进程 { // 判断操作类型是创建句柄还是复制句柄 if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE) { //是否具有关闭进程的权限,有的话删掉它 if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE) { //是否具有关闭进程的权限,有的话删掉它 if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } }exit: return OB_PREOP_SUCCESS;}
NTSTATUS SetThreadCallback(){ NTSTATUS status = STATUS_SUCCESS; OB_CALLBACK_REGISTRATION obCallbackReg = { 0 }; OB_OPERATION_REGISTRATION obOperationReg = { 0 };
RtlZeroMemory(&obCallbackReg, sizeof(OB_CALLBACK_REGISTRATION)); RtlZeroMemory(&obOperationReg, sizeof(OB_OPERATION_REGISTRATION));
// 设置 OB_OPERATION_REGISTRATION obOperationReg.ObjectType = PsThreadType; obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ThreadPreCall);
// 设置 OB_CALLBACK_REGISTRATION obCallbackReg.Version = ObGetFilterVersion(); obCallbackReg.OperationRegistrationCount = 1; obCallbackReg.RegistrationContext = NULL; RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900"); obCallbackReg.OperationRegistration = &obOperationReg;
// 注册回调函数 status = ObRegisterCallbacks(&obCallbackReg, &g_obThreadHandle); if (!NT_SUCCESS(status)) { DbgPrint("ObRegisterCallbacks Error[0x%X]\n", status); return status; }
return status;}
// 线程回调函数OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){ PEPROCESS pEProcess = NULL;
// 判断对象类型 if (*PsThreadType != pObPreOperationInfo->ObjectType) { return OB_PREOP_SUCCESS; } // 获取线程对应的进程 PEPROCESS pEProcess = IoThreadToProcess((PETHREAD)pObPreOperationInfo->Object); // 判断是否是要保护的进程, 若是, 则拒绝结束线程 if (IsProtectProcess(pEProcess)) { // 判断操作类型是创建句柄还是复制句柄 if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE) { //是否具有关闭线程的权限,有的话删掉它 if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE) { //是否具有关闭线程的权限,有的话删掉它 if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } }
return OB_PREOP_SUCCESS;}
BOOLEAN IsProtectProcess(PEPROCESS pEProcess){ BOOLEAN bRet = FALSE; PUCHAR pProcName = PsGetProcessImageFileName(pEProcess); // 获取要保护的进程名
if (pProcName) { if (strcmp(pProcName, PROCESS_NAME) == 0) { bRet = TRUE; } }
return bRet;}
VOID DriverUnload(IN PDRIVER_OBJECT driverObject){ // 删除进程回调 if (g_obProcessHandle) { ObUnRegisterCallbacks(g_obProcessHandle); g_obProcessHandle = NULL; }
// 卸载线程回调 if (NULL != g_obThreadHandle) { ObUnRegisterCallbacks(g_obThreadHandle); g_obThreadHandle = NULL; }
DbgPrint("驱动卸载完成\r\n");}


3


反对象监控


系统设置的对象回调函数会存储在一个名头CallbackList表头的双向链表里,它存储着系统上所有ObRegisterCallbacks对象回调地址,包括操作前和操作后的回调函数地址以及对象回调句柄信息。CallbackList双向链表的结构定义如下:
#pragma pack(1)typedef struct _OB_CALLBACK{ LIST_ENTRY ListEntry; ULONGLONG Unknown; HANDLE ObHandle; PVOID ObTypeAddr; PVOID PreCall; PVOID PostCall;}OB_CALLBACK, *POB_CALLBACK;#pragma pack()



如果想要获取进程回调的双向链表信息,可以从*PsProcessType中获取。要获得线程回调的双向链表信息,可以从*PsThreadType中获取。

*PsProcessType和*PsThreadType的数据结构类型为POBJECT_TYPE,定义如下:
typedef struct _OBJECT_TYPE{ LIST_ENTRY TypeList; // _LIST_ENTRY UNICODE_STRING Name; // _UNICODE_STRING PVOID DefaultObject; // Ptr64 Void UCHAR Index; // UChar ULONG TotalNumberOfObjects; // Uint4B ULONG TotalNumberOfHandles; // Uint4B ULONG HighWaterNumberOfObjects; // Uint4B ULONG HighWaterNumberOfHandles; // Uint4B OBJECT_TYPE_INITIALIZER TypeInfo; // _OBJECT_TYPE_INITIALIZER EX_PUSH_LOCK TypeLock; // _EX_PUSH_LOCK ULONG Key; // Uint4B LIST_ENTRY CallbackList; // _LIST_ENTRY}OBJECT_TYPE, *POBJECT_TYPE;

最后一个成员CallbackList就是双向链表表头。

而倒数第四个成员的类型为OBJECT_TYPE_INITIALIZER,它的定义如下:
typedef struct _OBJECT_TYPE_INITIALIZER{ USHORT Length; // Uint2B UCHAR ObjectTypeFlags; // UChar ULONG ObjectTypeCode; // Uint4B ULONG InvalidAttributes; // Uint4B GENERIC_MAPPING GenericMapping; // _GENERIC_MAPPING ULONG ValidAccessMask; // Uint4B ULONG RetainAccess; // Uint4B POOL_TYPE PoolType; // _POOL_TYPE ULONG DefaultPagedPoolCharge; // Uint4B ULONG DefaultNonPagedPoolCharge; // Uint4B PVOID DumpProcedure; // Ptr64 void PVOID OpenProcedure; // Ptr64 long PVOID CloseProcedure; // Ptr64 void PVOID DeleteProcedure; // Ptr64 void PVOID ParseProcedure; // Ptr64 long PVOID SecurityProcedure; // Ptr64 long PVOID QueryNameProcedure; // Ptr64 long PVOID OkayToCloseProcedure; // Ptr64 unsigned char#if (NTDDI_VERSION >= NTDDI_WINBLUE) // Win8.1 ULONG WaitObjectFlagMask; // Uint4B USHORT WaitObjectFlagOffset; // Uint2B USHORT WaitObjectPointerOffset; // Uint2B#endif}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

所以可以从*PsProcessType和*PsThreadType中获得链表头,然后遍历链表找到对应的句柄对象在调用ObUnRegisterCallbacks将回调删除,具体代码如下:
#include <ntifs.h>#include <wdm.h> #pragma pack(1)typedef struct _OBJECT_TYPE_INITIALIZER{ USHORT Length; // Uint2B UCHAR ObjectTypeFlags; // UChar ULONG ObjectTypeCode; // Uint4B ULONG InvalidAttributes; // Uint4B GENERIC_MAPPING GenericMapping; // _GENERIC_MAPPING ULONG ValidAccessMask; // Uint4B ULONG RetainAccess; // Uint4B POOL_TYPE PoolType; // _POOL_TYPE ULONG DefaultPagedPoolCharge; // Uint4B ULONG DefaultNonPagedPoolCharge; // Uint4B PVOID DumpProcedure; // Ptr64 void PVOID OpenProcedure; // Ptr64 long PVOID CloseProcedure; // Ptr64 void PVOID DeleteProcedure; // Ptr64 void PVOID ParseProcedure; // Ptr64 long PVOID SecurityProcedure; // Ptr64 long PVOID QueryNameProcedure; // Ptr64 long PVOID OkayToCloseProcedure; // Ptr64 unsigned char#if (NTDDI_VERSION >= NTDDI_WINBLUE) // Win8.1 ULONG WaitObjectFlagMask; // Uint4B USHORT WaitObjectFlagOffset; // Uint2B USHORT WaitObjectPointerOffset; // Uint2B#endif}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; typedef struct _OBJECT_TYPE{ LIST_ENTRY TypeList; // _LIST_ENTRY UNICODE_STRING Name; // _UNICODE_STRING PVOID DefaultObject; // Ptr64 Void UCHAR Index; // UChar ULONG TotalNumberOfObjects; // Uint4B ULONG TotalNumberOfHandles; // Uint4B ULONG HighWaterNumberOfObjects; // Uint4B ULONG HighWaterNumberOfHandles; // Uint4B OBJECT_TYPE_INITIALIZER TypeInfo; // _OBJECT_TYPE_INITIALIZER EX_PUSH_LOCK TypeLock; // _EX_PUSH_LOCK ULONG Key; // Uint4B LIST_ENTRY CallbackList; // _LIST_ENTRY}OBJECT_TYPE, *POBJECT_TYPE; typedef struct _OB_CALLBACK{ LIST_ENTRY ListEntry; ULONGLONG Unknown; HANDLE ObHandle; PVOID ObTypeAddr; PVOID PreCall; PVOID PostCall;}OB_CALLBACK, *POB_CALLBACK;#pragma pack() VOID DriverUnload(IN PDRIVER_OBJECT driverObject);BOOLEAN RemoveProcessObCallback();BOOLEAN RemoveThreadObCallback(); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){ NTSTATUS status = STATUS_SUCCESS; if (RemoveProcessObCallback()) { DbgPrint("删除进程回调成功\r\n"); } else { DbgPrint("删除进程回调失败\r\n"); } if (RemoveThreadObCallback()) { DbgPrint("删除线程回调成功\r\n"); } else { DbgPrint("删除线程回调失败\r\n"); }exit: driverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS;} BOOLEAN RemoveThreadObCallback(){ BOOLEAN bRet = TRUE; LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 获取线程表头 POB_CALLBACK pObCallback = NULL; pObCallback = (POB_CALLBACK)CallbackList.Flink; do{ if (!MmIsAddressValid(pObCallback)) { bRet = FALSE; break; } if (pObCallback->ObHandle) { ObUnRegisterCallbacks(pObCallback->ObHandle); DbgPrint("删除回调函数成功,函数地址:0x%X\r\n", pObCallback->PreCall); } } while (CallbackList.Flink != (PLIST_ENTRY)pObCallback); return bRet;} BOOLEAN RemoveProcessObCallback(){ BOOLEAN bRet = TRUE; POB_CALLBACK pObCallback = NULL; LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 获取设置进程对象回调函数的双向链表表头 pObCallback = (POB_CALLBACK)CallbackList.Flink; do{ if (!MmIsAddressValid(pObCallback)) { bRet = FALSE; break; } if (pObCallback->ObHandle) { ObUnRegisterCallbacks(pObCallback->ObHandle); DbgPrint("删除回调成功,函数地址为:0x%X\r\n", pObCallback->PreCall); } pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink; }while (CallbackList.Flink != (PLIST_ENTRY)pObCallback); return bRet;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){ DbgPrint("驱动卸载完成\r\n");}


4


运行结果


设置回调以后想要关闭进程就会失败:
将回调删除以后就可以正常关闭进程:



 


看雪ID:1900

https://bbs.pediy.com/user-home-835440.htm

*本文由看雪论坛 1900 原创,转载请注明来自看雪社区




# 往期推荐

1.Android Linker详解

2.vmp 相关的问题

3.记一次头铁的病毒样本分析过程

4.通过CmRegisterCallback学习注册表监控与反注册表监控

5.Android APP漏洞之战——权限安全和安全配置漏洞详解

6.全网最详细CVE-2014-0502 Adobe Flash Player双重释放漏洞分析



公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存